#include "efr.h"
#include "core.h"

/*
 * this function is used to rewrite the efr registers
 *
 * @param[in]  addr   efr registers address
 * @param[in]  wr_dt  the value you want to fill in
 */

void efr_io_output(uint8_t io, bool high_low)
{
    irq_disable();
    
    if(io > 0x22)
        return;

    if(io > 0x19){
        io = (io & 0x0F);
        /* set output high or low*/
        efr_change(PEXTCON2, ((1 << io) | (1 << io + 4)), ((uint8_t)high_low << io));
    }else{
        io = (io & 0x0F) - 5;
        /* set output high or low*/
        efr_change(PEXTCON0, ((1 << io) | (1 << io + 4)), ((uint8_t)high_low << io));
    }
    irq_enable();
}
/*
 * this function is used to rewrite the efr registers
 *
 * @param[in]  addr   efr registers address
 * @param[in]  wr_dt  the value you want to fill in
 */
void efr_write(uint8_t addr, uint8_t wr_dt)
{
    EFRADR = addr;
    EFRDAT = wr_dt;
}

/*
 * this function is used to read the efr registers
 *
 * @param[in]  addr  efr Register address
 * @return the value of Register
 */
uint8_t efr_read(uint8_t addr)
{
    uint8_t efr_data;

    EFRADR = addr;
    efr_data = EFRDAT;
    
    return efr_data;
}

/*
 * this function modifies the bits you want to modify
 *
 * @param[in]  addr          efr Register address
 * @param[in]  start_bit     the start bit that you want to modify
 * @param[in]  value         the value you want to change from the start bit
 * @param[in]  set_or_clear  select set or reset
 * @return the value of Register
 */
void efr_bit_change(uint8_t addr, uint8_t start_bit, uint8_t value, bool set_or_reset)
{
    uint8_t read_efr;
    bool EA_FLAG;

    EA_FLAG = EA;
    EA = 0;

    read_efr = efr_read(addr);
    read_efr &= ~(value << start_bit);
    if (set_or_reset)
        read_efr |= (value << start_bit);
    efr_write(addr, read_efr);

    EA = EA_FLAG;
}

/*
 * this function modifies the bits you want to modify
 *
 * @param[in]  addr          efr Register address
 * @param[in]  clear_mask    the value you want to clear
 * @param[in]  set_mask      the value you want to change
 * @return none
 */
void efr_change(uint8_t addr, uint8_t clear_mask, uint8_t set_mask)
{
    uint8_t read_efr;
    // read efr
    EFRADR = addr;
    read_efr = EFRDAT;
    // write efr
    EFRADR = addr;
    EFRDAT = ((read_efr & ~clear_mask) | set_mask);
}

/*
 * this function set the bits you want to modify
 *
 * @param[in]  addr          efr Register address
 * @param[in]  bitmask       the bitmask should be set
 */
void efr_set_bit(uint8_t addr, uint8_t bitmask)
{
    uint8_t read_efr;
    
    read_efr = efr_read(addr);
    read_efr |= bitmask;
    efr_write(addr, read_efr);
}

/*
 * this function clear the bits you want to modify
 *
 * @param[in]  addr          efr Register address
 * @param[in]  bitmask       the bitmask should be clear
 */
void efr_clear_bit(uint8_t addr, uint8_t bitmask)
{
    uint8_t read_efr;
    
    read_efr = efr_read(addr);
    read_efr &= ~bitmask;
    efr_write(addr, read_efr);
}

/*
 * this function toggle the bits you want to modify
 *
 * @param[in]  addr          efr Register address
 * @param[in]  bitmask       the bitmask should be clear
 */
void efr_toggle_bit(uint8_t addr, uint8_t bitmask)
{
    uint8_t read_efr;
    
    read_efr = efr_read(addr);
    read_efr ^= bitmask;
    efr_write(addr, read_efr);

}